home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / mega src / Source / cp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  11.8 KB  |  509 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     cp.c
  4.     
  5.     Copyright (c) 1993,1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #define    CP_BUF_SIZE    2048
  16.  
  17. #include <script.h>
  18. #include <string.h>
  19.  
  20. #include "nshc.h"
  21.  
  22. #include "arg_utl.proto.h"
  23. #include "fss_utl.proto.h"
  24. #include "fss_utl2.proto.h"
  25. #include "nshc_utl.proto.h"
  26. #include "str_utl.proto.h"
  27.  
  28. // data definition - this struct is the root of all data
  29.  
  30. typedef enum { copy_none, copy_data, copy_rsrc, copy_close } c_state;
  31.  
  32. typedef struct {
  33.  
  34.     int        got_fss;        // 0 if FSSpec calls are not available
  35.  
  36.     int        arg;            // position in arg list
  37.     
  38.     c_state    copy_state;        // in data or resource portion
  39.     
  40.     Boolean    isDir;            // if target is a directory
  41.     long    dirID;            // id of target if it is a directory
  42.  
  43.     FSSpec    toSpec;            // fsspec of output file
  44.     FSSpec    fromSpec;        // fsspec of input file
  45.     
  46.     short    toData;            // file ref. number, 0 if no file open
  47.     short    toRsrc;            // file ref. number, 0 if no file open
  48.     short    fromData;        // file ref. number, 0 if no file open
  49.     short    fromRsrc;        // file ref. number, 0 if no file open
  50.  
  51. } t_cp_data;
  52.  
  53. typedef    t_cp_data    **CDataH;
  54.  
  55. /* ======================================== */
  56.  
  57. // prototypes - utility
  58.  
  59. void cp_bad( t_nshc_parms *nshc_parms, int code );
  60. void cp_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  61. void cp_good( t_nshc_parms *nshc_parms );
  62.  
  63. // prototypes - file copy routines
  64.  
  65. void cp_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData );
  66. void cp_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData );
  67. void cp_read_write( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData );
  68.  
  69. // prototypes - state machine
  70.  
  71. void cp_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  );
  72. void cp_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  73. void cp_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  74.  
  75. /* ======================================== */
  76.  
  77. // utility routines
  78.  
  79. /* ======================================== */
  80.  
  81. void cp_bad(  t_nshc_parms *nshc_parms, int code )
  82. {
  83.     nshc_parms->action = nsh_stop;
  84.     nshc_parms->result = code;
  85. }
  86.  
  87. void cp_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  88. {
  89.     nshc_calls->NSH_putStr_err("\pcp: File access error (");
  90.     nshc_calls->NSH_putStr_err(msg);
  91.     nshc_calls->NSH_putStr_err("\p)\r");
  92.  
  93.     nshc_parms->action = nsh_stop;
  94.     nshc_parms->result = NSHC_ERR_GENERAL;
  95. }
  96.  
  97. void cp_good(  t_nshc_parms *nshc_parms )
  98. {
  99.     nshc_parms->action = nsh_stop;
  100.     nshc_parms->result = 0;
  101. }
  102.  
  103. /* ======================================== */
  104.  
  105. // file access routines
  106.  
  107. /* ======================================== */
  108.  
  109. void cp_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData )
  110. {
  111.     int        argc;
  112.     int        result;
  113.     char    *toStr;
  114.     
  115.     // strip off target path and process it
  116.  
  117.     argc = --nshc_parms->argc;
  118.     
  119.     toStr = &nshc_parms->arg_buf[ nshc_parms->argv[argc] ];
  120.     
  121.     if ( cStrEqual( toStr, "dev:tty" ) ) {
  122.         nshc_calls->NSH_putStr_err( "\pcp: \"dev:tty\" is not supported.\r" );
  123.         cp_bad( nshc_parms, NSHC_ERR_PARMS );
  124.         return;
  125.         }
  126.  
  127.     if ( cStrEqual( toStr, "dev:null" ) ) {
  128.         cp_good( nshc_parms );
  129.         return;
  130.         }
  131.         
  132.     result = arg_to_fss( nshc_parms, nshc_calls, argc, &(**hData).toSpec );
  133.     
  134.     if (result)
  135.         cp_bad( nshc_parms, result );
  136.     else{
  137.         result = fss_to_DirID( &(**hData).toSpec, &(**hData).dirID, &(**hData).isDir );
  138.         if (argc > 2)
  139.             if ( (result != noErr) || !(**hData).isDir ) {
  140.                 nshc_calls->NSH_putStr_err( "\pcp: Destination must be a directory when more than one file is copied.\r" );
  141.                 cp_bad( nshc_parms, NSHC_ERR_PARMS );
  142.                 }
  143.         }
  144. }
  145.  
  146. /* ======================================== */
  147.  
  148. void cp_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData )
  149. {
  150.     int        result;
  151.     long    dirID;
  152.     Boolean    isDir;
  153.     FInfo    fndrInfo;
  154.     long    newEOF;
  155.     long    oldEOF;
  156.     
  157.     // =====> convert "from" path to fsspec
  158.     
  159.     result = arg_to_fss( nshc_parms, nshc_calls, (**hData).arg, &(**hData).fromSpec );
  160.  
  161.     (**hData).arg++;
  162.     
  163.     if (result) {
  164.         cp_bad( nshc_parms, result );
  165.         return;
  166.         }
  167.     
  168.     result = fss_to_DirID( &(**hData).fromSpec, &dirID, &isDir );
  169.         
  170.     if (( result == noErr) && isDir) {
  171.         nshc_calls->NSH_putStr_err("\pcp: Skiping directory = ");
  172.         nshc_calls->NSH_putStr_err((StringPtr)(**hData).fromSpec.name);
  173.         nshc_calls->NSH_putchar('\r');
  174.         return;
  175.         }
  176.             
  177.     if ( result == fnfErr ) {
  178.         nshc_calls->NSH_putStr_err("\pcp: File not found = ");
  179.         nshc_calls->NSH_putStr_err((StringPtr)(**hData).fromSpec.name);
  180.         nshc_calls->NSH_putchar('\r');
  181.         return;
  182.         }
  183.             
  184.     if ( result ) {
  185.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).fromSpec.name );
  186.         return;
  187.         }
  188.             
  189.     // =====> if "to" is a real file, create it and write finfo
  190.         
  191.     result = fss_GetFInfo((**hData).got_fss, &(**hData).fromSpec, &fndrInfo);
  192.     
  193.     if ( result ) {
  194.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).fromSpec.name );
  195.         return;
  196.         }
  197.  
  198.     if ((**hData).isDir) {
  199.         (**hData).toSpec.parID = (**hData).dirID;
  200.         pStrCopy( (**hData).toSpec.name, (**hData).fromSpec.name );
  201.         }
  202.         
  203.     result =  fss_Delete((**hData).got_fss, &(**hData).toSpec);
  204.     
  205.     if ( ( result != noErr ) && ( result != fnfErr ) ) {
  206.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).toSpec.name );
  207.         return;
  208.         }
  209.  
  210.     result = fss_CreateResFile((**hData).got_fss, &(**hData).toSpec, fndrInfo.fdCreator, fndrInfo.fdType, smSystemScript);
  211.  
  212.     if ( result ) {
  213.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).toSpec.name );
  214.         return;
  215.         }
  216.  
  217.     // =====> open all the file devices
  218.         
  219.     result = fss_OpenDF((**hData).got_fss, &(**hData).fromSpec, fsRdPerm, &(**hData).fromData);
  220.     
  221.     if (!result)
  222.         result = fss_OpenRF((**hData).got_fss, &(**hData).fromSpec, fsRdPerm, &(**hData).fromRsrc);
  223.  
  224.     if (result) {
  225.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).fromSpec.name );
  226.         return;
  227.         }
  228.         
  229.     result = fss_OpenDF((**hData).got_fss, &(**hData).toSpec, fsRdWrShPerm, &(**hData).toData);
  230.  
  231.     if (!result)
  232.         result = fss_OpenRF((**hData).got_fss, &(**hData).toSpec, fsRdWrShPerm, &(**hData).toRsrc);
  233.  
  234.     if (result) {
  235.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).toSpec.name );
  236.         return;
  237.         }
  238.             
  239.     // =====> set the eofs to make sure there is disk space
  240.     // =====> if there is an error, restore the old eofs
  241.     
  242.     if (!result) {        // data fork
  243.     
  244.         result = GetEOF((**hData).toData, &oldEOF);
  245.         
  246.         if (!result)
  247.             result = GetEOF((**hData).fromData, &newEOF);
  248.         
  249.         if (!result)
  250.             result = SetEOF((**hData).toData, newEOF);
  251.     
  252.         if (result)
  253.             SetEOF((**hData).toData, oldEOF);
  254.         }
  255.  
  256.     if (!result) {        // rsrc fork
  257.     
  258.         result = GetEOF((**hData).toRsrc, &oldEOF);
  259.         
  260.         if (!result)
  261.             result = GetEOF((**hData).fromRsrc, &newEOF);
  262.         
  263.         if (!result)
  264.             result = SetEOF((**hData).toRsrc, newEOF);
  265.     
  266.         if (result)
  267.             SetEOF((**hData).toRsrc, oldEOF);
  268.         }
  269.         
  270.     if (result) {
  271.         cp_bad_file( nshc_parms, nshc_calls, "\pend of file" );
  272.         return;
  273.         }
  274.         
  275.     (**hData).copy_state = copy_data;
  276. }
  277.  
  278. /* ======================================== */
  279.  
  280. void cp_read_write( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData )
  281. {
  282.     int        close;
  283.     int        temp;
  284.     int        result;
  285.     long    bcount;
  286.     char    buf[CP_BUF_SIZE+1];
  287.     
  288.     result = close = 0;
  289.     
  290.     // =====> copy the data fork
  291.     
  292.     if ( (**hData).copy_state == copy_data ) {
  293.     
  294.         bcount = CP_BUF_SIZE;
  295.         result = FSRead( (**hData).fromData, &bcount, &buf );
  296.         
  297.         if (( result == noErr ) || ( result == eofErr )) {
  298.         
  299.             if (result == eofErr) {
  300.                 (**hData).copy_state = copy_rsrc;
  301.                 result = 0;
  302.                 }
  303.             
  304.             if (bcount && !result) {
  305.                 result = FSWrite( (**hData).toData, &bcount, &buf );
  306.                 if (result)
  307.                     cp_bad_file( nshc_parms, nshc_calls, "\pwrite data" );
  308.                 }
  309.             
  310.             }
  311.         else
  312.             cp_bad_file( nshc_parms, nshc_calls, "\pread data" );
  313.         }
  314.     
  315.     // =====> copy the resource fork
  316.     
  317.     if ( (**hData).copy_state == copy_rsrc ) {
  318.     
  319.         bcount = CP_BUF_SIZE;
  320.         result = FSRead( (**hData).fromRsrc, &bcount, &buf );
  321.         
  322.         if (( result == noErr ) || ( result == eofErr )) {
  323.         
  324.             if (result == eofErr) {
  325.                 (**hData).copy_state = copy_close;
  326.                 result = 0;
  327.                 }
  328.             
  329.             if (bcount && !result) {
  330.                 result = FSWrite( (**hData).toRsrc, &bcount, &buf );
  331.                 if (result)
  332.                     cp_bad_file( nshc_parms, nshc_calls, "\pwrite resource" );
  333.                 }
  334.             
  335.             }
  336.         else
  337.             cp_bad_file( nshc_parms, nshc_calls, "\pread resource" );
  338.  
  339.         }
  340.     
  341.     // =====> close the input file
  342.     
  343.     if ( (**hData).copy_state == copy_close ) {
  344.  
  345.         if ( (**hData).fromData ) {
  346.             if ( temp = FSClose( (**hData).fromData ) )
  347.                 result = temp;
  348.             (**hData).fromData = 0;
  349.             }
  350.     
  351.         if ( (**hData).fromRsrc ) {
  352.             if ( temp = FSClose( (**hData).fromRsrc ) )
  353.                 result = temp;
  354.             (**hData).fromRsrc = 0;
  355.             }
  356.     
  357.         if ( (**hData).toData ) {
  358.             if ( temp = FSClose( (**hData).toData ) )
  359.                 result = temp;
  360.             (**hData).toData = 0;
  361.             }
  362.     
  363.         if ( (**hData).toRsrc ) {
  364.             if ( temp = FSClose( (**hData).toRsrc ) )
  365.                 result = temp;
  366.             (**hData).toRsrc = 0;
  367.             }
  368.         
  369.         (**hData).copy_state = copy_none;
  370.         
  371.         if (result)
  372.             cp_bad_file( nshc_parms, nshc_calls, "\pclose file" );
  373.         
  374.         }
  375. }
  376.  
  377. /* ======================================== */
  378.  
  379. // state machine - core routines
  380.  
  381. /* ======================================== */
  382.  
  383. void cp_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  )
  384. {
  385.     CDataH    hData;    // handle to hold our data
  386.     
  387.     if (nshc_parms->argc < 3) {
  388.         nshc_calls->NSH_putStr_err( "\pUsage: see \"man cp\" for options.\r" );
  389.         cp_bad( nshc_parms, NSHC_ERR_PARMS );
  390.         return;
  391.         }
  392.         
  393.     nshc_parms->action = nsh_continue;
  394.  
  395.     hData = (CDataH)NewHandleClear(sizeof(t_cp_data));
  396.     
  397.     if (hData) {
  398.         (**hData).arg = 1;                    // start at the arg = 1 position
  399.         (**hData).got_fss = fss_test();        // test if we can use FSSpec calls
  400.         nshc_parms->data = (Handle)hData;
  401.         HLock( hData );
  402.         cp_setup( nshc_parms, nshc_calls, hData );
  403.         HUnlock( hData );
  404.         }
  405.     else {
  406.         nshc_calls->NSH_putStr_err( "\pcp: Could not allocate storage.\r" );
  407.         cp_bad( nshc_parms, NSHC_ERR_MEMORY );
  408.         }
  409. }
  410.  
  411. /* ======================================== */
  412.  
  413. void cp_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  414. {
  415.     CDataH    hData;
  416.     
  417.     if (hData = (CDataH)nshc_parms->data) {
  418.  
  419.         if ((**hData).copy_state == copy_none) {
  420.         
  421.             if ((**hData).arg >= nshc_parms->argc) {
  422.                 cp_good( nshc_parms );
  423.                 return;
  424.                 }
  425.     
  426.             HLock( hData );
  427.             cp_open( nshc_parms, nshc_calls, hData );
  428.             HUnlock( hData );
  429.             }
  430.         
  431.         if ((**hData).copy_state != copy_none) {
  432.         
  433.             HLock( hData );
  434.             cp_read_write( nshc_parms, nshc_calls, hData );
  435.             HUnlock( hData );
  436.             
  437.             }
  438.         }
  439. }
  440.  
  441. /* ======================================== */
  442.  
  443. void cp_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  444. {
  445.     short    fRef;
  446.     OSErr    error;
  447.     CDataH    hData;
  448.     int        temp;
  449.     int        result;
  450.     
  451.     result = 0;
  452.     
  453.     if (hData = (CDataH)nshc_parms->data) {
  454.     
  455.         if ( (**hData).fromData ) {
  456.             if ( temp = FSClose( (**hData).fromData ) )
  457.                 result = temp;
  458.             (**hData).fromData = 0;
  459.             }
  460.     
  461.         if ( (**hData).fromRsrc ) {
  462.             if ( temp = FSClose( (**hData).fromRsrc ) )
  463.                 result = temp;
  464.             (**hData).fromRsrc = 0;
  465.             }
  466.     
  467.         if ( (**hData).toData ) {
  468.             if ( temp = FSClose( (**hData).toData ) )
  469.                 result = temp;
  470.             (**hData).toData = 0;
  471.             }
  472.     
  473.         if ( (**hData).toRsrc ) {
  474.             if ( temp = FSClose( (**hData).toRsrc ) )
  475.                 result = temp;
  476.             (**hData).toRsrc = 0;
  477.             }
  478.         
  479.         DisposeHandle(nshc_parms->data);
  480.         }
  481.         
  482.     if (result)
  483.         cp_bad_file( nshc_parms, nshc_calls, "\pclosing files" );
  484.         
  485.     nshc_parms->action = nsh_idle;
  486. }
  487.  
  488. /* ======================================== */
  489.  
  490. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  491. {
  492.     
  493.     if (nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION )) return;
  494.     
  495.     switch (nshc_parms->action) {
  496.         case nsh_start:
  497.             cp_start(nshc_parms, nshc_calls);
  498.             break;
  499.         case nsh_continue:
  500.             cp_continue(nshc_parms, nshc_calls);
  501.             break;
  502.         case nsh_stop:
  503.             cp_stop(nshc_parms, nshc_calls);
  504.             break;
  505.         }
  506. }
  507.  
  508. /* ======================================== */
  509.